
#include <stdint.h>
#include "PoolPort.h"
#include "MPool.h"
#include "contract.h"

#define DIM(array_) (sizeof(array_) / sizeof((array_)[0]))


struct BlockInfo_Tag {
    uint8_t poolId;
    uint8_t used;
};
typedef struct BlockInfo_Tag BlockInfo_T;

static MPool pools[4];
static uint_fast8_t maxPool;

void Pool_Init(void * const poolSto, uint_fast32_t const poolSize,
               uint_fast16_t const blockSize) {
    /** @pre cannot exceed the number of available memory pools */
    REQUIRE(maxPool < (uint_fast8_t)DIM(pools));
    /** @pre please initialize event pools in ascending order of blockSize: */
    REQUIRE((maxPool == (uint_fast8_t)0)
            || (pools[maxPool - (uint_fast8_t)1].blockSize
                < blockSize));

    /* perform the initialization of the pool */
    MPool_Init(&pools[maxPool], poolSto, poolSize, blockSize);
    ++maxPool; /* one more pool */
}

void *Pool_Alloc(uint_fast16_t const blockSize) {
    void *b;
    BlockInfo_T* blockInfo;
    uint_fast8_t idx;
    uint_fast16_t allocSize;

    allocSize = blockSize + sizeof(BlockInfo_T);

    /* find the pool index that fits the requested block size ... */
    for (idx = (uint_fast8_t)0; idx < maxPool; ++idx) {
        if (allocSize <= pools[idx].blockSize) {
            break;
        }
    }

    /* cannot run out of registered pools */
    ASSERT(idx < maxPool);

    b = MPool_Get(&pools[idx]);
	if(b != (void*)0){
		blockInfo = (BlockInfo_T*)b;
		blockInfo->poolId = idx;
		blockInfo->used = (uint8_t)1;	/*set used flag, use to check mult free*/
		return (void*)(blockInfo + 1); /* can't be NULL */
	}
    /* must tolerate bad alloc. */
    ASSERT(b);
    return b;
}


void Pool_Free(void * const b) {
    BlockInfo_T* blockInfo;

    REQUIRE(b);

    blockInfo = (BlockInfo_T*)b - 1;	/*get block info*/
    REQUIRE(blockInfo->poolId < maxPool);
    REQUIRE(blockInfo->used == (uint8_t)1);

    blockInfo->used = (uint8_t)0;	/*clear used flag, for mult free check*/
    MPool_Put(&pools[blockInfo->poolId], (void *) blockInfo);
}


